package org.acooke.uykfd.db

import java.io.File
import java.lang.Long
import java.sql.Connection
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.TransformerFactory

import org.apache.empire.db.DBReader
import org.apache.empire.db.DBRecord

import scala.xml.Elem
import scala.xml.Node
import scala.xml.XML

object Dump {

  def dumpAll(dir: File, cnxn: Connection) {
    checkDir(dir)
    assert(dir.listFiles.length == 0, dir.getPath + " must be empty")
    process(dump, dir, cnxn)
  }

  def restoreAll(dir: File, cnxn: Connection) {
    checkDir(dir)
    process(restore, dir, cnxn)
  }

  private def checkDir(dir: File) {
    assert(dir.exists, dir.getPath + " must exist")
    assert(dir.isDirectory, dir.getPath + " must be a directory")
  }

  private def process(action: (ScalaTable[_], File, Connection) => Unit, dir: File, cnxn: Connection) {
    for (table <- Schema.orderedTables) {
      try {
        println(table.getName)
        action(table, dir, cnxn)
      } catch {
        case x: AssertionError => println(x)
        case x: Exception => println(x)
      }
    }
  }

  private def tableFile(table: ScalaTable[_], dir: File) = new File(dir, table.getName + ".sql")

  private def dump(table: ScalaTable[_], dir: File, cnxn: Connection) = {
    val cmd = Schema.createCommand
    cmd.select(table.getColumns)
    val reader = new DBReader
    try {
      reader.open(cmd, cnxn)
      val xml = reader.getXmlDocument
      val source = new DOMSource(xml)
      val file = tableFile(table, dir)
      val result = new StreamResult(file)
      val xformer = TransformerFactory.newInstance.newTransformer
      xformer.transform(source, result)
    } finally {
      reader.close
    }
  }

  private def restore(table: ScalaTable[_], dir: File, cnxn: Connection) {
    val file = tableFile(table, dir)
    assert(file.exists, file.getPath + " must exist")
    assert(file.isFile, file.getPath + " must be a file")
    val cmd = Schema.createCommand
    val xml = XML.loadFile(file)
    val columns = for (column <- xml \\ "column") yield (column \ "@name" text)
    for (row <- xml \\ "row") {
      cmd.clearSet()
      for (column <- columns) {
        val value = try {
            (row \\ column)(0).text
          } catch {
            case _ => row \\ ("@"+column.toLowerCase)
          }
        cmd.set(table.getColumn(column).to(value))
      }
      Schema.executeSQL(cmd.getInsert, cnxn)
    }
    if (table.orm.isInstanceOf[IdTable[_,_,_]]) {
      val idCmd = Schema.createCommand
      idCmd.select(table.getColumn("ID").max)
      val nextId = Integer.toString(1 + (Schema.querySingleValue(idCmd.getSelect, cnxn) match {
        case i: Integer => i.intValue
        case l: Long => l.intValue
        case x => println(x); throw new Exception("Failed to read max(ID) for " + table.getName)
      }))
      Schema.executeSQL("ALTER SEQUENCE " + table.getName + "_SEQ RESTART WITH " + nextId, cnxn)
    }
  }

}
